/* Copyright  2009-2010
   @Author
   Richard Changde Yin            e-mail yinchangde@hotmail.com

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/


/**
 *@filename: databaseManagerImpl.h
 */
#ifndef __DATABASE_MANAGER_IMPL_H__
#define __DATABASE_MANAGER_IMPL_H__

#include <os.h>
#include <catalogtables.h>
#include <lock.h>
#include <databaseManager.h>

#include <process.h>
#include <util.h>

//Note::DatabaseManagerImpl is used to hide functionalities from normal database user.
//User is exposed to DatabaseManagerImpl, for our tools we shall type cast
//DatabaseManager to DatabaseManagerImpl to retrieve internal information
//such as db statistics, etc
class Database;
class Session ;


class Table;
class mm_handler ;

class ChunkIterator;
class Chunk;
class TransactionManager;

class DBSqlProcInfo
{
public:
    DBSqlProcInfo():sysDbAttachAddr  (0),
                    userDbAttachAddr (0)
                    {}
    void * sysDbAttachAddr;
    void * userDbAttachAddr;
};

//Global object
static DBSqlProcInfo dbsqlProcInfo;


class Identifier;
class DatabaseManagerImpl : public DatabaseManager
{
private:
    //pointer to system Database
    Database* systemDatabase_;

    //pointer to database
    Database* db_;


    LockManager *       lMgr_;

    TransactionManager *tMgr_;

    ProcessManager *    pMgr_;

    int procSlot;

    //BackEnd::List tableHandleList;  list of table handles

    //only Session creates object of this class
    inline DatabaseManagerImpl():systemDatabase_(NULL),
                                 db_ (NULL),
                                 lMgr_(NULL),
                                 tMgr_(NULL),
                                 pMgr_(NULL)
                        {
                          procSlot = -1;
                          errkey   = -1;
                        }
    ~DatabaseManagerImpl();
    ///   Open system Database;
    BackEnd::DbRetVal openSystemDatabase();
    ///   Close system Database;
    BackEnd::DbRetVal closeSystemDatabase();
    ChunkIterator getSystemTableIterator(CatalogTableID id);
    Chunk* getSystemTableChunk(CatalogTableID id);



    BackEnd::DbRetVal createHashIndex(const char *indName,
                                      Table& tbl,
                                      IndexInfo *  indxptr ,
                                      const char *tableName,
                                      uint32_t  fldsize,
                                      int bucketSize,
                                      bool isUnique,
                                      bool isPrimary    = false ,
                                      bool  b_checkTable= false ,
                                      bool b_wlock      = true );


    BackEnd::DbRetVal quick_createHashIndex_part1
                                     (const char *indName,
                                      const char *fldName,
                                      Table& tbl,
                                      HashIndexInfo *info,
                                      void*  chunk,
                                      void*  tptr ,
                                      char** fptr ,
                                      void*& tupleptr
                                      );

    BackEnd::DbRetVal quick_createHashIndex_part2
                                     (const char *indName,
                                      const char *fldName,
                                      Table& tbl         ,
                                      HashIndexInfo *info,
                                      void* chunk        ,
                                      void* tupleptr
                                      );
    /*
    BackEnd::DbRetVal createTreeIndex(const char *indName,
                                      Table& tbl,
                                      const char *tableName,
                                      M_FieldList &fldList,
                                      int bucketSize,
                                      bool isUnique,
                                      bool isPrimary = false);
    */
    void initHashBuckets(Bucket *buck, int bucketSize);

    void destroyHashBuckets(Bucket *buck, int bucketSize);

    BackEnd::DbRetVal dropIndexInt(const char *name,
                                   void* tptr, bool takeLock);


    BackEnd::DbRetVal insertIndexNodeToTable( void * chunk   ,
                                              Table& tbl     ,
                                              void *indexPtr ,
                                              IndexInfo *info )   ;
    uint32_t get_encoded_data_length(CTABLE* tptr,const unsigned char* record);

    uint32_t process_record_data_to_chunkset(CTABLE* tptr,
                                             const unsigned char *record,
                                             unsigned char *pos,
                                             uint32_t is_compare);

    void  mm_extract_record   (CTABLE* tptr, unsigned char *record,
                                       const unsigned char *pos);
public:

    //pointer to system Database
    static Database* g_systemDatabase;

    //pointer to database
    static Database* g_database;

    static uint32_t initDataBase() ;

    static uint32_t endDataBase()  ;

    inline Database* db()    { return db_; }

    inline Database* sysDb() { return systemDatabase_; }

    inline void setSysDb(Database *i_db) { systemDatabase_ = i_db; }

    inline void setDb(Database *i_db)    { db_ = i_db; }

    void createLockManager();
    void createTransactionManager();

    void setProcSlot();

    inline TransactionManager* txnMgr() { return tMgr_; }

    inline LockManager* lockMgr()       { return lMgr_; }

    //for user database file there is no limit for the number
    //of tables or chunks
    BackEnd::DbRetVal createDatabase(const char *name, size_t size);
    BackEnd::DbRetVal deleteDatabase(const char *name);

    BackEnd::DbRetVal openDatabase(const char *name);
    BackEnd::DbRetVal closeDatabase();


    BackEnd::DbRetVal createTable(const char *name,Table& def,
                                  HA_CREATE_INFO *create_info,
                                  bool internal_table = 0 );

    BackEnd::DbRetVal dropTable(const char *name);

    int openTable(const char *name,Table* tbl, bool b_creatIdx = true) ;

    int quick_openTable(const char *name,
                        Table* tbl,
                        void*  chunk,
                        void*  tptr ,
                        char** fptr ,
                        bool b_creatIdx = true) ;

    void closeTable(Table *table);

    BackEnd::DbRetVal checkTableExists(const char *name,bool b_getlock=true);

    BackEnd::DbRetVal createIndex(const char *indName,
                                  Table& tble        ,
                                  IndexInfo *info,
                                  bool b_withlock = true );

    BackEnd::DbRetVal quick_createHashIndex_wrapper
                                  (const char *indName, /*idx name*/
                                   const char *fldName, /* field name*/
                                   Table& tbl,          /* table reference*/
                                   HashIndexInfo *info,
                                   void*  chunk,
                                   void*  tptr ,
                                   char** fptr);

    BackEnd::DbRetVal dropIndex  (const char *name,
                                  void* tptr,
                                  bool takeLock = true);

    BackEnd::DbRetVal disableIndex(Table& tbl, void* tptr);

    BackEnd::DbRetVal enableIndex(Table& tbl, void* tptr);

    BackEnd::DbRetVal is_indexes_are_disabled(Table& tbl, void* tptr);

    BackEnd::DbRetVal newRecord(Table& tbl,const unsigned char *record);

    BackEnd::DbRetVal delete_all_rows(Table& tbl);

    BackEnd::DbRetVal delete_row(Table& tbl,MM_INFO* mminfo, unsigned char *record);

    void getInfo(MM_INFO* mminfo);

    int mm_rkey(Table& tbl,MM_INFO* mminfo, unsigned char *record, int inx,
                const unsigned char *key,
                key_part_map keypart_map, enum ha_rkey_function find_flag);

    int mm_rfirst(Table& tbl,MM_INFO* mminfo,unsigned char *record, int inx);

    int mm_rnext(Table& tbl,MM_INFO* mminfo,unsigned char *record, int inx);

    int mm_rnext_same(Table& tbl,MM_INFO* mminfo,unsigned char *buf);


    BackEnd::DbRetVal registerThread();
    BackEnd::DbRetVal deregisterThread();

    bool isAnyOneRegistered();
    void printUsageStatistics();
    void printDebugLockInfo();
    void printDebugTransInfo();
    void printDebugChunkInfo();
    void printDebugProcInfo();
    BackEnd::DbRetVal printIndexInfo(char *name);
    Chunk* createUserChunk(size_t size = 0);
    Chunk* createUserIndexChunk (size_t size = 0);
    BackEnd::DbRetVal deleteUserChunk(Chunk *chunk);
    BackEnd::DbRetVal deleteUserIndexChunk (Chunk *chunk);
    int errkey ;

    friend class Session;
    friend class mm_handler;
    friend class LockManager;
};
#endif  //__DATABASE_MANAGER_IMPL_H__
